/*    Copyright 2010 Tobias Marschall
 *
 *    This file is part of MoSDi.
 *
 *    MoSDi is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    MoSDi is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with MoSDi.  If not, see <http://www.gnu.org/licenses/>.
 */

package mosdi.tests;

import java.util.ArrayList;
import java.util.List;

import junit.framework.TestCase;
import mosdi.discovery.IidBoundCalculator;
import mosdi.fa.Alphabet;
import mosdi.fa.CDFA;
import mosdi.fa.DFAFactory;
import mosdi.fa.GeneralizedString;
import mosdi.fa.IIDTextModel;
import mosdi.paa.ClumpSizeCalculator;
import mosdi.util.Iupac;
import mosdi.util.IupacStringConstraints;
import mosdi.util.iterators.IupacPatternIterator;

public class IidBoundCalculatorTest extends TestCase {

	public void testBounds() {
		double[] charDist = {0.15, 0.35, 0.3, 0.2};
		int[] minFrequencies = {0,0,0,1};
		int[] maxFrequencies = {4,1,2,1};
		int length = 4;
		final Alphabet dnaAlphabet = Alphabet.getDnaAlphabet();
		final Alphabet iupacAlphabet = Alphabet.getIupacAlphabet();
		IupacStringConstraints constraints = new IupacStringConstraints(minFrequencies, maxFrequencies);
		IupacPatternIterator it = new IupacPatternIterator(length, constraints);
		IidBoundCalculator ibc = new IidBoundCalculator(it.peek(), charDist, constraints);
		final double accuracy = 1e-10;
		while (it.hasNext()) {
			int[] s = it.next();
//			System.out.println("------");
//			System.out.println(Iupac.getAlphabet().buildString(s));
			List<GeneralizedString> l = new ArrayList<GeneralizedString>();
			l.add(Iupac.toGeneralizedString(iupacAlphabet.buildString(s)));
			CDFA cdfa = DFAFactory.build(dnaAlphabet, l, 50000);
			double expectation = 0.0;
			for (GeneralizedString p : l) expectation+=p.getProbability(charDist);
			ClumpSizeCalculator csc = new ClumpSizeCalculator(new IIDTextModel(dnaAlphabet.size(), charDist), cdfa, s.length);
			double[] clumpSizeDist = csc.clumpSizeDistribution(20, 1e-30);
			double expectedClumpSize = 0.0;
			for (int i=1; i<clumpSizeDist.length; ++i) {
				expectedClumpSize+=clumpSizeDist[i]*i;
			}
			
			double expLowerBound = 0.0;
			double expUpperBound = 1.0;
			double expClumpSizeUpperBound = Double.POSITIVE_INFINITY;
			for (int prefixLength=0; prefixLength<=length; ++prefixLength) {
				if (prefixLength>0) {
					ibc.setPatternPosition(prefixLength-1, s[prefixLength-1]);
				}
				double newExpLowerBound = ibc.getExpectationLowerBound(prefixLength);
				double newExpUpperBound = ibc.getExpectationUpperBound(prefixLength);
				double newExpClumpSizeUpperBound = ibc.getExpectedClumpSizeUpperBound(prefixLength);
//				System.out.println(String.format("exp. lower: %f --> %f", expLowerBound, newExpLowerBound));
//				System.out.println(String.format("exp. upper: %f --> %f", expUpperBound, newExpUpperBound));
//				System.out.println(String.format("exp. clump size upper: %f --> %f", expClumpSizeUpperBound, newExpClumpSizeUpperBound));
				assertTrue(newExpLowerBound<=expectation+accuracy);
				assertTrue(newExpUpperBound>=expectation-accuracy);
				assertTrue(newExpLowerBound>=expLowerBound-accuracy);
				assertTrue(newExpUpperBound<=expUpperBound+accuracy);
				assertTrue(newExpLowerBound<=newExpUpperBound+accuracy);
				assertTrue(newExpClumpSizeUpperBound<=expClumpSizeUpperBound+accuracy);
				assertTrue(newExpClumpSizeUpperBound>=expectedClumpSize-accuracy);
				expLowerBound = newExpLowerBound;
				expUpperBound = newExpUpperBound;
				expClumpSizeUpperBound = newExpClumpSizeUpperBound;
			}
			assertEquals(expLowerBound, expUpperBound, 1e-10d);
		}
	}

	
}
